#include "wxx_error.hpp"
#include <boost/format.hpp>

wxx::wxx_error::~wxx_error()
{
	if (m_what)
	{
		local_allocator<char> alloc;
		alloc.deallocate(const_cast<char*>(m_what));
		
		m_what = NULL;
	}

	if (m_info)
	{
		m_info->Release();
		m_info = NULL;
	}
}

const char* wxx::wxx_error::what() const
{
	if (!m_what)
	{
		if (m_info)
		{
			BSTR description;
			
			if (SUCCEEDED(m_info->GetDescription(&description)))
			{
				::SysFreeString(description);
			}
			else
			{
			}
		}
		else
		{
			m_what = format_system_message(m_hr);
		}
	}

	return m_what;
}

const char* wxx::wxx_error::format_system_message(HRESULT hr)
{
	using boost::format;
	using std::string;

	char* buffer = NULL;

	if (!::FormatMessageA(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL, hr, 0,
		reinterpret_cast<LPSTR>(&buffer),
		0, NULL))
	{
		format fmt = 
			format("FormatMessage failed with 0x%1$08x.") 
			% ::GetLastError();

		std::string str(fmt.str());

		buffer = local_allocator<char>().allocate(str.length());		
		str.copy(buffer, str.length());
	}

	return buffer;
}

void wxx::ensure_success_hr(HRESULT hr, IErrorInfo* info) throw(...)
{
	if (FAILED(hr))
	{
		wxx::wxx_error::throw_hr(hr, info);
	}
}

void wxx::ensure_success_win32(BOOL result) throw(...)
{
	if (result == 0)
	{
		wxx::wxx_error::throw_last_win32();
	}
}

HANDLE wxx::ensure_success_win32(HANDLE result) throw(...)
{
	if (result != 0)
	{
		return result;
	}

	wxx::wxx_error::throw_last_win32();
}
